2021 CryptoCTF
1 | Crypto CTF is an online competition for hackers to test, evaluate, and expand their cryptography exploiting skills. In this CTF, we will provide various crypto challenges regarding modern cryptography techniques. |
这两天在复现2022-CryptoCTF,但是想着2021的CryptoCTF也没复现完,于是就决定先从2021开始了。
Farm
POINTS:41
考点:有限域,逐字节爆破
1 | #!/usr/bin/env sage |
这道题目,生成了一个F = list(GF(64)),这里用sagemath测试一下,得到的是
1 | [0, |
长度正好是64。ok,虽然不是很明白怎么来的,但是可以先放一边。然后看到程序调用了keygen(l)函数,
1 | def keygen(l): |
该函数首先生成长度为l的数组,元素取自F,最后prod所有的元素,但由于其结果仍会在F这个galois-field中,所以到这里已经可以预见这道题怎么做了,只用穷举一下这个F中的所有元素当作key即可,只有64种可能。
然后我们看具体的加密流程以编写解密算法。
1 | def encrypt(msg, key): |
重点在enc += ALPHABET[F.index(pkey * maptofarm(chr(m)))]
看到算法是对明文逐位字节加密的,并且根据这个比赛的flag格式,我们知道明文前三个字节应该是‘CCT’,那么也就知道了其base64编码所以,我们可以先爆破出密钥,然后逐字节爆破明文
exp:
1 | import string, base64, math |
Keybase
POINTS:48
考点:AES-CBC模式
1 | #!/usr/bin/env python3 |
是一道需要交互的题目,那么我们看到题目提供的功能。
一个是 g,会将flag的密文输出
1 | if ans == 'g': |
一个是 t,接受32字节的消息加密,然后输出密钥前14字节,以及相应密文,不过会对密文第一组做一个隐藏处理,只给出第一组开头和结尾共4个字节
1 | elif ans == 't': |
而加密和解密使用的是AES-CBC模式
所以这里的切入点很明确,就是利用功能 t,
- 首先我们发送两组共32字节的明文 “A”*32 过去,会得到14字节的密钥和一组模糊密文和一组清晰密文
- 我们爆破密钥的剩余两个字节,然后用爆破出来的密钥尝试对第二组密文进行解密,解密后的结果和第一组模糊密文中的清晰部分进行异或,如果得到的均为”A“,则我们的密钥爆破正确。
- 由于CBC模式,我们还需要iv。此时我们拥有密钥,明文;如果拥有第一组密文,我们对第一组密文进行解密并与明文异或即可知道iv
- 需要意识到的是,第一组密文用于第二组明文加密,而第二组明文我们又是知道的,所以我们使用密钥解密第二组密文,并与第二组明文异或得到第一组密文,然后解密第一组密文,与第一组明文异或,得到iv
- 使用密钥和iv解密flag的密文,获取flag
脚本改编自https://blog.cryptohack.org/cryptoctf2021-easy#keybase
1 | from pwn import * |
Rima
POINTS:56
考点:爆破,信息恢复
1 | #!/usr/bin/env python |
这道题的函数很简单,一个nextPrime,顾名思义。
然后程序对flag取二进制,然后在最开始插入一个0。如果flag是这个比赛的常规flag,那么会以‘C’开头,而‘C’的ASCII码的二进制是“01‘开头,所以补上这个0后,不出意外这个f数组的长度应该是8 * len(flag)。
1 | f = [int(x) for x in bin(int(FLAG.hex(), 16))[2:]] |
然后进行一个操作,f数组的每一个(除了最后一个)元素赋值为当前元素和后一个元素值之和。
1 | for i in range(len(f)-1): |
然后程序获取三个值 a = nextPrime(len(f)), b = nextPrime(a), c = nextPrime(len(f) >> 2)。三个值的取值只与flag的长度相关。(那么显然最后可以通过爆破flag的长度来解题)
1 | a = nextPrime(len(f)) |
然后是有点绕的一个数组生成 ,其实就是将数组f 分别重复 a次 和 b次。
1 | g, h = [[_ for i in range(x) for _ in f] for x in [a, b]] |
接着给g,h前面插c个0,
然后与之前类似的一个操作,g和h数组的每一个(除了后面c个)元素赋值为当前元素和后C个元素值之后。
1 | for _ in [g, h]: |
类似这样两个数组相加。最后还将当前得到的值拼接,视为五进制
1 | g, h = [int(''.join([str(_) for _ in __]), 5) for __ in [g, h]] |
所以解题思路就很清晰。
首先我们爆破flag的长度,我们知道密文的长度为 a * f + c 和 b * f + c,而a ,b,c 又和f直接相关,所以这很好判断。
然后我们先恢复这个”移位C“的向量加,以上图为例,由于最后结果仍然保留了原来g数组的开头和结尾,故中间部分是很好恢复的。
最后我们在恢复一个”移位1“的向量加即可解出flag。
(其实用不到两个enc,有一个就够了。)
exp.py
1 | from Crypto.Util.number import * |
Titu
POINTS:69
考点:丢番图方程
1 | #!/usr/bin/env python3 |
代码倒是不多,眼瞅着就是一道数学题
解方程 $(x^2+1)\cdot(y^2+1)-2\cdot(x-y)(xy-1) == 4\cdot(k+xy)$
用sage整理一下
1 | sage: var('x,y') |
$(x^2+1)\cdot(y^2+1)-2\cdot(x-y)(xy-1) - 4xy = ((x+1)(y+1))^2$
那看看这个 k 是不是平方数
1 | sage: k |
$k=(2\cdot 3\cdot 11^2\cdot 19\cdot 47\cdot 71\cdot 3449\cdot 11953\cdot 5485619\cdot 2035395403834744453 \cdot 17258104558019725087 \cdot 1357459302115148222329561139218955500171643099)^2$
那开个方的话,就是解 $(x+1)(y+1)=2^2\cdot 3\cdot 11^2\cdot 19\cdot 47\cdot 71\cdot 3449\cdot 11953\cdot 5485619\cdot 2035395403834744453 \cdot 17258104558019725087 \cdot 1357459302115148222329561139218955500171643099$
然后这里 x 和 y 的长度大小应该是比较接近的,emmm,排列组合一下?方程右边的分一分,给到 (x+1) 和 (y+1)
或者换个意思,显然 $(x+1) \mid 2\sqrt{k}$,遍历一下 $2\sqrt{k}$ 的因子那就
脚本来自https://blog.cryptohack.org/cryptoctf2021-easy#titu
1 | from Crypto.Util.number import * |
Symbols
POINTS:70
考点:latex
h, my eyes, my eyes! People still can solve this kind of cryptography? Mathematicians should love this one!
1 | \Cap \Cap \Theta \Finv \{ \Pi \ltimes \aleph y \_ \wp \infty \therefore \heartsuit \_ \Lsh \aleph \Theta \eth \Xi \} |
$\Cap \Cap \Theta \Finv { \Pi \ltimes \aleph y _ \wp \infty \therefore \heartsuit _ \Lsh \aleph \Theta \eth \Xi }$
CCTF{Play_with_LaTeX}
Hyper Normal
POINTS:71
考点:Matrix,爆破
1 | import random |
分析上述源码,可以知道,
transpose函数为矩阵转置
1 | def transpose(x): |
vsum函数为向量加法
1 | def vsum(u, v): |
sprod函数为向量的倍增
1 | def sprod(a, u): |
看到加密函数encrypt
首先生成hyper向量,向量的每个值与flag每个字节相关,为 $ord(flag_i) \cdot (i+1), i \in [0,len(flag)]$,
然后用hyper向量生成对角矩阵V,效果为$[a,b,c,d,e] \rightarrow$ $$\begin{bmatrix}a&0&0&0&0\newline 0&b&0&0&0\newline 0&0&c&0&0\newline 0&0&0&d&0\newline 0&0&0&0&e\newline\end{bmatrix}$$
然后利用shuffle函数扰乱一下行向量。
1 | def encrypt(msg): |
之后生成 l 个 R向量,用于生成w矩阵,规则为v = vsum(v, sprod(R[j], V[j]))
1 | for _ in range(l): |
可以知道,这样乘了之后,之前对于V的shuffle对于结果来说其实是没有意义。由于我们并不关心 R 的实际顺序,于是等价生成了R矩阵$$\begin{bmatrix}R_{00}&R_{01}&R_{02}&R_{03}&R_{04}\newline R_{10}&R_{11}&R_{12}&R_{13}&R_{14}\newline R_{20}&R_{21}&R_{22}&R_{23}&R_{24}\newline R_{30}&R_{31}&R_{32}&R_{33}&R_{34}\newline R_{40}&R_{41}&R_{42}&R_{43}&R_{44}\newline \end{bmatrix}$$,然后和矩阵$$V=\begin{bmatrix}a&0&0&0&0\newline 0&b&0&0&0\newline 0&0&c&0&0\newline 0&0&0&d&0\newline 0&0&0&0&e\newline\end{bmatrix}$$相乘。
然后这里还有一个random.shuffle(transpose(W))函数,但是这里 shuffle 的其实是矩阵transpose(W),而函数返回的是W矩阵,所以这句代码对返回结果其实没有任何影响。
那么我们得到矩阵 $$M = \begin{bmatrix}a \cdot R_{00} &b \cdot R_{01} &c \cdot R_{02}&d \cdot R_{03}&e \cdot R_{04}\newline a \cdot R_{10} &b \cdot R_{11}&c \cdot R_{12}&d \cdot R_{13}&e \cdot R_{14}\newline a \cdot R_{20}&b \cdot R_{21}&c \cdot R_{22}&d \cdot R_{23}&e \cdot R_{24}\newline a \cdot R_{30}&b \cdot R_{31}&c \cdot R_{32}&d \cdot R_{33}&e \cdot R_{34}\newline a \cdot R_{40}&b \cdot R_{41}&c \cdot R_{42}&d \cdot R_{43}&e \cdot R_{44}\newline \end{bmatrix}$$
而加密函数中两次shuffle都没了任何影响。
如果此时不是由于模运算的存在且p = 8443 太小了。那么我们对矩阵列向量求一个gcd就能过获取flag的每一个字节的值了。
所以这里的另辟蹊径。由于模运算的存在显然是逆不回去了,我们选择正向爆破。
由于这里的$R_{ij} \in(0,126)$,那么我们就尝试所有的 $R$ 和每一个可见字符
1 | for c in printable: |
如果flag密文向量中的每一个值都存在于 possibilities 向量中,那么则说明我们对于该密文向量我们的明文字符选取正确。
脚本来自 https://blog.cryptohack.org/cryptoctf2021-easy#hyper-normal
1 | from string import printable |
Salt and Pepper
POINTS:71
考点:哈希拓展攻击
1 | #!/usr/bin/env python3 |
看到获取flag的条件
1 | if USERNAME in inp_username and PASSWORD in inp_password: |
USERNAME 要在 inp_username 中,PASSWORD 要在 inp_password 中
然后满足
1 | sha1(pepper + password + md5(salt + username).hexdigest().encode('utf-8')).hexdigest() == h |
其中 salt,pepper 未知,但是知道 md5(salt) 和 sha1(pepper)以及salt 和 pepper 的长度;inp_username,inp_password,inp_hash可控。那么显然这里是一个哈希长度拓展攻击了。
我们知道salt的长度以及哈希,那么我们可以使用哈希拓展攻击,附加上username 并获取到 md5(salt + username) 的哈希。
./hash_extender -f md5 -d -s 5f72c4360a2287bc269e0ccba6fc24ba -a n3T4Dm1n -l 19
得到
1
295623660d3d04c7680a52679e35f041c
\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00n3T4Dm1n然后我们知道 pepper 的长度以及哈希,还知道 password,我们再次使用哈希拓展攻击,附加上 password+md5(salt + username) 的哈希并获取到最终的哈希
1
./hash_extender -f sha1 -d -s 3e0d000a4b0bd712999d730bc331f400221008e0 -a P4s5W0rd95623660d3d04c7680a52679e35f041c -l 19
得到
1
283875efbe020ced3e2c5ecc908edc98481eba47f
\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98P4s5W0rd95623660d3d04c7680a52679e35f041c那么我们以
用户名:
\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x00\x00\x00\x00n3T4Dm1n
密码:
\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98P4s5W0rd
哈希:
83875efbe020ced3e2c5ecc908edc98481eba47f
作为输入即可通过验证,获取flag
工具hash_extender来自github:https://github.com/iagox86/hash_extender
下述脚本来自:https://pwnthenope.pythonanywhere.com/writeups/salt_and_pepper.html
1 | from pwn import remote, process |
Hamul
POINTS:83
考点:RSA
1 | from Crypto.Util.number import * |
emmm,RSA经典整活,就是分解特殊构造的n。
我们设 $x=len(q),y=len(p),x’=len(Q),y’=len(P)$)
那么有
$PP = P \cdot 10^{x’} + Q = (p\cdot 10^{x} +q)\cdot 10^{x’} + (q\cdot 10^{y} +p)=p\cdot (10^{x+x’})+q\cdot (10^{x’}+10^{y})+p$
$QQ = Q \cdot 10^{y’} + P = (q\cdot 10^{y} +p)\cdot 10^{y’} + (p\cdot 10^{x} +q) =q \cdot(10^{y+y’}) + p \cdot(10^y+10^{y’})+q$
$N = PP \cdot QQ = pq\cdot10^{x+x’+y+y’} + \cdots+p\cdot q$
只要我们能够解出 $pq$,因为他只有 128bit,能够大力分解,然后我们就可以解题了。
看着这里 N 的形式,本地测一下,会发现 N 的最高十八位就是 $pq$ 的高位,N 的最低十八、十九位就是 $pq$ 的低位。然后中间会缺一到两位,要爆破一下。
脚本来自https://blog.cryptohack.org/cryptoctf2021-easy#hamul
1 | from Crypto.Util.number import * |
Triplet
POINTS:91
考点:RSA,欧拉函数
1 | #!/usr/bin/env python3 |
可以看到题目逻辑很简单,就是让你输入三对 p,q,在同一对 e,d的情况下,均满足 $e \cdot d \equiv 1 \pmod {(p-1) \cdot (q-1)}$
1 | if 1 < e < min([phi_1, phi_2, phi_3]) and 1 < d < min([phi_1, phi_2, phi_3]): |
满足 $e \cdot d \equiv 1 \pmod {(p-1) \cdot (q-1)}$,显然会满足 $e \cdot d \equiv 1 \pmod {LCM((p-1) \cdot (q-1))}$
那么很直观的,我们想要找到一个素数 $p_0$,满足 $p_1 = \frac{p_0-1}{2}+1$ 也是一个素数,这样$(p_1-1)\cdot(q-1) = \frac{(p_0-1)}{2}\cdot(q-1)$,就能够满足条件。
同理可以再找一个$p_2 = \frac{p_0-1}{4}+1$
最后找一个合适的公钥e,1 < e < min([phi_1, phi_2, phi_3]),然后生成私钥 d = inverse(e,min([phi_1, phi_2, phi_3])),就能够通过验证,获取flag。
何为合适?能过所有的assert的呗。(因为这里要求d = inverse(e,min([phi_1, phi_2, phi_3])),所以会满足 $e \cdot d \equiv 1 \pmod{(p-1)\cdot(q-1)}$ ,但不一定满足$e \cdot d \equiv 1 \pmod{2\cdot (p-1)\cdot(q-1)}$
exp.py
1 | from Crypto.Util.number import * |
Onlude
POINTS:95
考点:线性代数
1 | #!/usr/bin/env sage |
看看怎么处理flag的先
1 | def cross(m): |
建了个 $11 \times 11$ 的零矩阵,然后将 flag 的每一个字符转化为在字符集里的索引放了进去,两两间隔4个元素,类似这样
1 | [11 0 0 0 0 11 0 0 0 0 11] |
然后生成了一个密钥
1 | def keygen(): |
R 和 S 是一个随机矩阵,
L,U 分别是 S的下三角矩阵和上三角矩阵,会有 $S==L \times U$
然后就是加密
1 | def encrypt(A, key): |
$E = L^{-1} \times Y = L^{-1} \times S \times X $
$E = L^{-1} \times L \times U \times(A+R) $
$E = U \times A + U \times R$
然后题目提供了 $L \times U \times L,L^{-1} \times S^2 \times L,R^{-1} \times S^8$
想法就是怎么用题目提供的这几个东西把 $E$ 里的 $A$ 提出来叭
首先的一个想法是把 $R$ 搞出来,因为 $E$ 里面有 $R$,
因为我们有 $R^{-1} \times S^8$,所以我们搞到 $S^8$ 就行
$S^8 = (L \times U)^8 = (L \times U \times L \times U)^4$
因为我们有 $L \times \ U \times L$ ,所以我们搞到 $U$ 就行
注意到 $L^{-1} \times S^2 \times L = L^{-1} \times (L \times U)^2 \times L = U \times L \times U \times L$
所以我们也能搞到 $U$
然后我们就能从 $E$ 中提出 $A$ 来,从而获取flag了。
脚本来自https://blog.cryptohack.org/cryptoctf2021-medium#onlude
1 | E = Matrix(GF(71),[[25,55,61,28,11,46,19,50,37,5,21], |
Maid
POINTS:119
考点:Rabin Cryptosystem
1 | #!/usr/bin/python3 |
这里用的是 Rabin 密码系统,但是 $n=p^2 q$
然后题目提供三个功能,
e:使用公钥加密 $c \equiv msg^2 \pmod n$
d:使用私钥解密 未知
s:给出flag的密文 $c \equiv m^{65537} \pmod n$
$n$ 也没给,不过这好搞,用两次加密功能,然后 $gcd(m_1^2-c_1,m_2^2-c_2)$ 就好了。
问题出在源码没有给出这个rabin密码系统的解密代码,那么只能fuzz一下,看有没有机会分解出 $p,q$ 来。
一般都是会传一下特殊的值,比如1,0,-1这样去fuzz,但是由于本地没法搭环境,就没法自己搞测试样例了,还挺麻烦的。
(这里后面放出源码了,就模拟一下当时的场景好了。)
1 | def decrypt(c, privkey): |
这里本地测试的时候,会发现有时候,解密的值再加密,并不能变回去,感觉就挺奇怪的。
然后测试会发现 $gcd(D(-1)-1,n) \neq 1$
那么就能分解n了,然后就是常规解密 RSA 的操作了。
脚本来自 https://blog.cryptohack.org/cryptoctf2021-medium#maid
1 | from pwn import * |
这里我们回头看一下解密函数
$m_p \equiv c^{(p+1)/4} \pmod p$
$i=(c-m_p^2)//p$
$j \equiv \frac{i} {2 \cdot m_p} \pmod p$
$m = m_p + j \cdot p$
如果 $m \ge \frac{p^2}{2},return \ p^2 -m,$
如果 $m \lt \frac{p^2}{2},return \ m,$
最初加密的时候似乎也限制了 $m \lt 2^{2\cdot 1024 -2} = 2^{2046} \le p^2$
推导一下,如果传过去正常的明文 $m$,我们得到密文 $m^2 \pmod {p^2 q}$
(不难知道 $c \equiv m^2 \pmod p$,$c \equiv m^2 \pmod {p^2}$,$c \equiv m^2 \pmod q$ )
$m_p \equiv (m^2)^{(p+1)/4} \equiv m^{(p+1)/2} \equiv m \cdot m^{(p-1)/2}\equiv \pm m \pmod p$
$i = (m^2 - m_p^2 ) // p = (m^2 + k_1p^2q - m^2 - k_2p)//p=k_1pq-k_2$
$j \equiv \frac{i}{2m_p} \equiv \frac{k_1pq-k_2}{2m_p} \equiv \frac{-k_2}{2m_p}\pmod p $
$m = m_p + j \cdot p = m_p + \frac{-k_2p}{2m_p} $ 这一步似乎是想得到 $m \pmod {p^2}$ ?
如果传 $-1$ 去解密就会有
$m_p \equiv (-1)^{(p+1)/4} \equiv 1 \ or -1\pmod p $
如果 $m_p=1$:
$i = (-1 - 1)// p = -1$
$j \equiv -2^{-1} \pmod p$
$m = 1 +j \cdot p $
那么 $gcd(m-1,n) = gcd(j\cdot p ,p^2 q) = p$
如果 $m_p=-1$:
$i = (-1 - 1- k_1p)// p = -k_1$
$j \equiv \frac{k_1}{2}\pmod p$
$m = -1 + j \cdot p $ (然而好像触发 $m \ge \frac{p^2}{2},return \ p^2 -m,$,所以得到 $m = 1-j\cdot p +p^2 $)
那么 $gcd(m-1,n) = gcd(p^2-j\cdot p ,p^2 q) = p$
比赛的时候没有给出解密函数,,emmm,就会觉得有一点点脑洞。
Wolf
PONITS:128
考点:爆破
1 | #!/usr/bin/env python3 |
看到题目的附件,好像把AES-GCM加密用的key都给出来了
1 | passphrase = b'HungryTimberWolf' |
然后iv没给,长度也不确定,但是在1 和 11之间
1 | niv = os.urandom(random.randint(1, 11)) |
emmm,那就暴力连接,当niv=1的时候,再爆破一下niv的值进行解密,一共也就256种可能。
期望概率大概也就是 $\frac{1}{11 \cdot 256}$
1 | from pwn import * |
Ferman
POINTS:134
考点:高斯整数
1 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
经典给出 $p,q$ 相关额外信息进行对 $n$ 的分解。
给出 $hint = (p-127)^2 + (q-184)^2$
这里经过测试发现 $hint$ 是一个七次幂,即 $hint = z ^7$
1 | sage: w=13809252727788824044233595548226590341967726502046327883413398709726819135921363848617960542444505497356040393690402758557636039683075007984614264314802550433942617885990971202110511768121760826488944622697964930982921462840320850014092598270493079542993367042001339267321218767132063176291998391714014192946596879176425904447127657664796094937171819714510504836456988487840790317576922986001688147359646287894578550322731904860694734616037751755921771706899493873123836562784063321 |
设$x=p-127,y=q-184$
那么我们有 $x^2+y^2 = z^7$
由于 $x^2+y^2 = (x+iy)(x-iy)$,
若我们能将 $z$ 分解成共轭的两部分$z_x,z_y$,那么就会有 $x+iy=z_x^7 \ or \ x+iy=z_y^7 $
1 | sage: C = ZZ[i] |
很对称,但是emmm,排列组合太多了,,我们可以换一组数据
1 | a = 2265 |
1 | a = 2265 |
测试
1 | w = 24007015341450638047707811509679207068051724063799752621201994109462561550079479155110637624506028551099549192036601169213196430196182069103932872524092047760624845002308713558682251660517182097667675473038586407097498167776645896369165963981698265040400341878755056463554861788991872633206414266159558715922583613630387512303492920597052611976890648632123534922756985895479931541478630417251021677032459939450624439421018438357005854556082128718286537575550378203702362524442461229 |
返回
1 | 3515251100858858796435724523870761115321577101490666287216209907489403476079222276536571942496157069855565014771125798502774268554017196492328530962886884456876064742139864478104832820555776577341055529681241338289453827370647829795170811402 |
于是我们得到素数
1 | x+2265=3515251100858858796435724523870761115321577101490666287216209907489403476079222276536571942496157069855565014771125798502774268554017196492328530962886884456876064742139864478104832820555776577341055529681241338289453827370647829795170813667 |
1 | from Crypto.Util.number import * |
(PS:对于方程$x^2+y^2=z^7$,我们利用高斯分解似乎能够找到很多组满足条件的解 $x,y$,取决于高斯分解 $z$ 后它能有多少个因子)
RSAphantine
POINTS:142
考点:丢番图方程
1 | 2*z**5 - x**3 + y*z = 47769864706750161581152919266942014884728504309791272300873440765010405681123224050402253883248571746202060439521835359010439155922618613520747411963822349374260144229698759495359592287331083229572369186844312169397998958687629858407857496154424105344376591742814310010312178029414792153520127354594349356721 |
题目的target很明显了,显然解关于x,y,z的方程组了。
$2z^5 - x^3 + yz=a $
$x^4+y^5+xyz=b$
$y^6+2z^5+zy=c$
很直观的会想要用3式减去 1式
$y^6+x^3=c-a$
用sage处理一下
1 | sage: f=y^6+x^3 |
(感觉出题人处理的比较好,c-a只有两个因子)那么显然,这里有 $y^2+x=3133713317731333$
有了这一条我们再代入 $f=y^6+x^3$ 就可以解出 $x,y$ 了
有了 $x,y$ 代入 2 式就能解出 $z$ 了。
从而进行RSA参数的生成,解密获得flag。
脚本来自https://jsur.in/posts/2021-08-01-crypto-ctf-2021-writeups
1 | from Crypto.Util.number import * |
FROZEN
POINTS: 142
考点:已知明文攻击(非预期?)
1 | from Crypto.Util.number import * |
题目是一个签名服务,使用私钥对4个字节的明文进行签名 $sign = priv_i \cdot m_p \pmod p$
$p$ 是一个约为 30bit 的素数
私钥的生成来源于 $r^is \pmod p,i \in [0,1,2,3,4]$ 的低 32 位。
但是题目给出了一个消息的签名示例,利用其 $msg,sign$,我们可以恢复 $priv_i \pmod p$
但是由于 $p$ 只有30比特左右,所以我们还需要做一点点小小的爆破,而判断依据则是 $(pub_i + pri_i) / (pub_{i-1}+pri_{i-1}) \equiv r \pmod p$
exp
1 | from Crypto.Util.number import * |
PS:这道题的flag是 CCTF{Lattice_bA5eD_T3cHn1QuE_70_Br34K_LCG!!}
,看来作者原意应该是让我们有lattice去恢复未知位,不过这里通过已知明文攻击能够获取到的低位太多了,这里需要再稍微调整一下。
LINDA
POINTS:169
考点:离散对数,$p-1$ 光滑
1 | #!/usr/bin/env python3 |
这道题目有一个 from secret import p
,交互获取样例会发现 $p-1$ 是光滑的
1 | p = 31236959722193405152010489304408176327538432524312583937104819646529142201202386217645408893898924349364771709996106640982219903602836751314429782819699 |
然后 $u,v,w$ 已知,再由
$$
cc \equiv m \cdot w^{r+s} \pmod p \
cb \equiv v^s \pmod p \
ca \equiv u^r \pmod p
$$
我们对 $ca,cb$ 解离散对数就能获取 $s,r$,然后就能计算 $w^{r+s}$,从而解密获取 $m$
exp
1 | # sage |
PS:这道题能有这么高的分倒是有点不可思议,可能大部分选手没发现 $p-1$ 是光滑的叭。
TinyECC
POINTS:217
考点:椭圆曲线离散对数
1 | #!/usr/bin/env python3 |
题目的意思是让你输入系数 $a,b,p$ 来构造一条曲线,然后解一个椭圆曲线上的离散对数问题。
这里有两个思路,一个是构造 $#E_p = p$,使用smart attack,或者 $#E_p = p-1, #E_p = p+1$ 可以使用weil pair 去做。
这里是用smart attack的方法,先根据http://www.monnerat.info/publications/anomalous.pdf生成奇异曲线的参数
1 | # http://www.monnerat.info/publications/anomalous.pdf |
对于第一条曲线我们就可以用smart attack进行离散对数的求解了,
那么第二条曲线,我们就遍历一下,尽量找一条比较光滑的曲线,以便直接使用pohlig-hellman对其继续离散对数求解。
1 | for param in curves: |
一个例子
1 | # E2.order() = 2 * 11 * 29 * 269 * 809 * 1153 * 5527 * 1739687 * 272437559 * 1084044811 |
然后进行 smart attack 和 discrete_log
1 | def SmartAttack(P,Q,p): |
交互拿到flag:CCTF{ECC_With_Special_Prime5}
不过还有比较简单的方法(也许是非预期),这里只检查了 $a\cdot b = 0?$ 而不是在模 $p$ 下,所以这里可以绕过,从而构造一条奇异曲线 $y^2 \equiv x^3 \pmod p$
这样就有同态 $E(x,y) \to \frac{x}{y}$,离散对数解起来就很方便了。
1 | p = 227297987279223760839521045903912023553 |
以上脚本来自https://blog.cryptohack.org/cryptoctf2021-hard#tiny-ecc
ELEGANT CURVE
POINTS:217
考点:椭圆曲线离散对数
1 | from Crypto.Util.number import * |
和上面的差不多,不过这次要输入两条曲线各自的 $a,b,p$,也限制了$p-q<2022,$ $a,b,c,d$ 也必须是大于 $0$,小于 $p$ 或者 $q$ 的,这样我们就不能用 $a=b=0$ 或者是 $a,b = kp$ 这样去构造奇异曲线 $y^2 \equiv x^3 \pmod p$ 了,那就还是用TinyECC那边的smartattack叭,找到一条奇异曲线,然后设 $q = nextprme(p)$,再改变合适的系数使得 $#Eq$ 是光滑的(前面是变 $q$,这里是变 $a,b$,都大差不差的),这样离散对数好求。
下面是一组示例
1 | q = 730750818665451459112596905638433048232067472077 |
1 | p = 730750818665451459112596905638433048232067471723 |
1 | from random import getrandbits |
flag: CCTF{Pl4yIn9_Wi7H_ECC_1Z_liK3_pLAiNg_wiTh_Fir3!!}
PS:感觉这两道题也可以控制参数使得两条曲线的阶都是比较光滑的,然后再解离散对数?
DOUBLE MIFF
POINTS:217
考点:椭圆曲线与丢番图方程
1 | from Crypto.Util.number import * |
根据题目我们有曲线 $ax(y^2 - 1)\equiv by(x^2-1) \pmod p$,其中曲线参数 $a,b,p$ 均未知,但是我们有 $P+P,Q+Q,P+Q$,$p$ 总是要恢复的叭,需要用到给出的三个点。那么通过这三个点,我们有等式 $(P+P) + (Q+Q) = 2 \cdot (P+Q)$,我们设 $2\cdot (P+Q)=(x_0,y_0),P+Q=(x_1,y_1),Q+Q=(x_2,y_2),P+P=(x_3,y_3)$,那么我们有
$$
x_0 \equiv \frac{(x_2+x_3)\cdot(1+y_2y_3)}{(1+x_2x_3)(1-y_2y_3)} \pmod p
$$
$$
x_0 \equiv \frac{2x_1(1+y_1^2)}{(1+x_1^2)(1-y_1^2)} \pmod p
$$
两式相减我们有
$$
(x_2+x_3)\cdot(1+y_2y_3) \cdot (1+x_1^2)(1-y_1^2)-2x_1(1+y_1^2)\cdot(1+x_2x_3)(1-y_2y_3) \equiv 0 \pmod p
$$
同理,由 $y$ 坐标的计算公式我们可以得到
$$
(y_2+y_3)\cdot(1+x_2x_3) \cdot (1+y_1^2)(1-x_1^2)-2y_1(1+x_1^2)\cdot(1+y_2y_3)(1-x_2x_3) \equiv 0 \pmod p
$$
两个模 $p$ 同余 $0$ 式子,我们求一个 $gcd$ 就能获取 $p$ 的一个倍数了,分解一下应该就能获取素数 $p$。
回到曲线的式子 $ax(y^2-1) \equiv by(x^2-1)$,对于两个未知数,emmm,我们给他搞成一个先 ,故而有
$$
k \equiv \frac{a}{b} \equiv \frac{y(x^2-1)}{x(y^2-1)}
$$
于是只需要一个点我们就能知道 $k \equiv \frac {a}{b}$,换一换也有
$$
k\frac{x}{x^2-1} \equiv \frac{y}{y^2-1}
$$
我们设 $P=(x_4,y_4)$,那么根据加法规则,我们有
$$
x_3 \equiv \frac{2x_4(1+y_4^2)}{(1+x_4^2)(1-y_4^2)} \pmod p
$$
$$
y_3 \equiv \frac{2y_4(1+x_4^2)}{(1+y_4^2)(1-x_4^2)} \pmod p
$$
两式相乘,我们有
$$
x_3y_3 \equiv \frac{4x_4y_4}{(x_4^2-1)(y_4^2-1)} \equiv 4k(\frac{x_4}{x_4^2-1})^2 \pmod p
$$
于是我们有
$$
(\frac{x_4^2-1}{x_4})^2 \equiv \frac{4k}{x_3y_3} \pmod p
$$
因为 $p \equiv 3 \pmod 4$,于是我们设 $l \equiv (\frac{4k}{x_3y_3})^{\frac{p+1}{4}}$,则有 $\frac{x_4^2-1}{x_4} \equiv \pm l$
于是我们有 $-x_4^2 \pm lx_4 +1 \equiv 0\pmod p$,解一手二次方程,$x \equiv \frac{\mp l \pm \sqrt{l^2+4}}{2}$ ,我们就能够拿到 $P$ 啦,同理也可以这么去拿$Q$,然后就能恢复 flag了。
1 | #!/usr/bin/env python3 |
ECCHIMERA
POINTS:271
考点:椭圆曲线离散对数,smart attack,pohlig-hellman
1 | from sage.all import * |
n可以分解
1 | n = 43216667049953267964807040003094883441902922285265979216983383601881964164181 |
第一部分
kp=p,smart attack
第二部分
sage: factor(kq)
2^4 * 3 * 13 * 233 * 4253 * 49555349 * 7418313402470596923151
但是直接discrete_log好像不行,这里选择放弃因子 3(Gq的阶没有因子3) 和 最大的 7418313402470596923151(数值太大) ,然后手撸一个pohlig hellman (也可以调参调用discrete_log,但好慢,感觉不如手撸)
1 | primes = [2^4,13, 233, 4253, 49555349] #don't use 3 and last one, cuz last one is too big, and 3 is not Gq's order's factor |
最后再crt一下就好了
1 | #!/usr/bin/env sage |
flag:CCTF{m1X3d_VeR5!0n_oF_3Cc!}
主要因为 $flag < Gp.order \cdot Gq.order / 7418313402470596923151 $ ,所以我们才能解出flag。
ROHALD
POINTS:180
考点:椭圆曲线、Edwards Curve、Montgomery、Weierstrass
1 | #!/usr/bin/env sage |
首先还是要获取椭圆曲线的参数 $c,d,p$
对于 $p$ 的获取,由于我们知道四个点 $P,Q,sP,tQ$
根据曲线我们有 $x^2+y^2 \equiv c^2(1+dx^2y^2) \pmod p$
所以如果有两个点,我们就能够得出 $c^2d$
$X_1 = x_1^2 +y_1^2-c^2(1+dx_1^2y_1^2) = k_1p$
$X_2 = x_2^2 +y_2^2-c^2(1+dx_2^2y_2^2) = k_2p$
两式相减我们有 $X_1-X_2 = (x_1^2+y_1^2-x_2^2-y_2^2)-c^2d(x_1^2y_1^2-x_2^2y_2^2) = (k_1-k_2)p \equiv 0 \pmod p$
于是 $c^2d \equiv \frac{(x_1^2+y_1^2-x_2^2-y_2^2)}{x_1^2y_1^2-x_2^2y_2^2} \pmod p$ ,可求
有了 $c^2d$,我们就能求出 $X_1-X_2=(k_1-k_2)p$ 了,
同理我们用另外两个点就能够搞出 $X_3-X_4 = (k_3-k_4)p$ 了,然后 gcd一下,再factor一下,就能够求出 $p$ 了。
有了$c^2d$,根据 $X_1 = x_1^2 +y_1^2-c^2(1+dx_1^2y_1^2) \equiv 0 \pmod p$ 也能求出 $c^2$ 了,从而也能求出 $d$ 了。
1 | from math import gcd |
脚本来自https://blog.cryptohack.org/cryptoctf2021-hard#rohald(注意 $c^2$ 开根的时候有两个解,最后解flag的时候都要尝试一下)
然后我们得转化这个椭圆曲线的形式,从Edwards Curve 转到 Montgomery形式最后变成Weierstrass形式,然后会发现这条曲线的阶光滑,直接调用 sagemath 的 discrete_log 就能进行求解。
$E_{c,d} : u^2 + v^2 -c^2 (1+du^2v^2)=0$
$u_{P+Q} = \frac{(u_Pv_Q)+(v_Pu_Q)}{c(1+du_Pu_Qv_Pv_Q)}$
$v_{P+Q}=\frac{(-u_Pv_Q)+(v_Pu_Q)}{c(1-du_Pu_Qv_Pv_Q)}$
Edwards Curve to $u’^2 + v’^2 =1+d’u’^2v’^2$ $(d’=dc^4,u’ = \frac{u}{c},v’=\frac{v}{c})$
to Montgomery $By’^2=x’^3+Ax’^2+x$ $(x’=\frac{1+v’}{1-v’},y’=\frac{2(1+v’)}{u’(1-v’)},A=\frac{2(1+d’)}{1-d’},B = \frac{1}{1-d’})$
to Weierstrass $y^2 =x^3 +ax+b$ $(x = \frac{x’}{B}+\frac{A}{3B},y=\frac{y’}{B},a=\frac{3-A^2}{3B^2},b=\frac{2A^3-9A}{27B^3})$
1 | def to_elliptic_2(P, p, c, d): |
脚本来自 https://zhuanlan.zhihu.com/p/399487467
ROBERT
POINTS:194
考点: carmichael_lambda
1 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
给出一个值 $s$,求 $lcm(n)=s$ 的 $n$,一个想法是通过查找 $s$ 的因子 $x,y$, 如果 $x+1,y+1$ 为素数,并且满足 $lcm(x,y)=s$,那么我们有 $n = (x+1)\cdot(y+1)$
1 | def reverse_lambda(n): |
TRUNC
POINTS:334
考点:Signature forgery
1 | #!/usr/bin/env python3 |
可以被非预期,
注意到验签函数:$k = hus^{-1},l=v\cdot s^{-1}$,其中$u,v,s$ 可控,验证 $(kG+(n-l)P)_x\equiv u \pmod n$
若目标消息哈希为 $h$,我们构造任意消息哈希为 $h’$,并且设 $m \equiv \frac{h}{h’} \pmod n$,
随后我们让服务端签名我们的消息,并得到签名 $u’,v’,s’$,此时 $k’=h’u’s’^{-1},l’=v’\cdot s’^{-1}$,该组 $(k,l)$能通过验证。
那么我们在伪造签名时只要设 $u=u’,s=s’m,v=v’m$,
就会有 $k = h’mu’(s’m)^{-1}=h’u’s’^{-1},l=v’m(s’m)^{-1}=v’s’^{-1}$,由上可知,该组 $(k,l)$ 能通过验证。
1 | #!/usr/bin/env python3 |
CCTF{__ECC_Bi4seD_N0nCE_53ns3_LLL!!!}
(PS:不过看着flag,估计要构造格,又非预期了,,,)
MY SIEVE
POINTS:477
考点:RSA
1 | enc = 17774316754182701043637765672766475504513144507864625935518462040899856505354546178499264702656639970102754546327338873353871389580967004810214134215521924626871944954513679198245322915573598165643628084858678915415521536126034275104881281802618561405075363713125886815998055449593678564456363170087233864817 |
题目还给了一个msieve文件,里面有一个
1 | 0x1dabd3bb8e99101030cd7094eb15dd525cb0f02065694604071c2a8b10228f30cc12d08fc9caa8d97c65ff481 |
似乎是 $n$ 的一个因子,
且已经有了分解
1 | 11 |
注意到公钥文件里面有四个 *,是被“污染”的 $n$,
这里一个想法是爆破一下,64**4 的复杂度,还好。但是好像最后也没结果。
然后用一用非预期(如果 $flag$ 比较小的话),尝试在“子剩余系“下解密
1 | from Crypto.Util.number import * |
成了!
那如果 flag 比较大怎么办?
(PS:
赛后没有被“污染”的公钥文件公布了,发现
1 | a='''-----BEGIN PUBLIC KEY----- |
发现除了 * 处,还有其他地方也不一样,,emmm,不是很懂出题人啥意思。
DORSA
POINTS:450
考点:RSA
1 | #!/usr/bin/env python3 |
根据 题目,我们有
$$
p=uv+1,q=vy+1,r=xy+1,s=kv+1,\phi=(p-1)(r-1)=uvxy,ed\equiv 1\pmod \phi,k=(ed-1)/\phi
$$
其中 $e.nbits \approx 256$
注意到
$$
\frac{n_2}{n_1} = \frac{qs}{pr}=\frac{(uy+1)(kv+1)}{(uv+1)(xy+1)}\approx\frac{uykv}{uvxy}=\frac{k}{x}
$$
所以 $k,x$ 有可能会在 $n2,n1$ 的连分数上(具体的关系没有推,做题的时候可以本地测几组数据)
(这里假设 $gcd(k,x)=1$ 了,但是也不一定是 1 叭,但也应该不大,可以小爆破一下?)
有了 $k,x$ 后,我们有
$$
k\phi+1 =ed\equiv 0 \pmod e \to \phi \equiv -1 \cdot k^{-1} \pmod e
$$
$$
\phi =uvxy \equiv 0 \pmod x
$$
有这两条同余式,我们能恢复 $\phi$ 大约 1024bit的信息,即 $\phi \pmod {ex}$。
另外
$$
| \phi -n_1|=|(p-1)(r-1)-pr| \approx p+q \le 2^{513}
$$
由于 $ex$ 大约有 $512$ 比特,我们首先设 $\phi’ = \phi % ex + k\cdot ex$,$k$ 值大约使得我们的 $\phi’$ 和 $n_1$ 一个数量级,然后再在小范围爆破一下即可恢复 $\phi$,从而解密获得 $flag$
exp,来自https://blog.cryptohack.org/cryptoctf2021-hard#dorsa
1 | from tqdm import |
(PS:看这flag,又非预期了似乎。。。。)
POLISH
POINTS:477
考点:RSA,Partial Key Exposure Attack
1 | m = bytes_to_long(flag) |
根据题目,我们已知 $n,d_{lsb}$,和一个丢番图方程。显然获得flag,除了把 RSA 解密,我们还得解这个丢番图方程获取 $x,y$
那么,先看看怎么解这个丢番图方程,我们有
$$
x^2(y-a)+y^2(x-a)=b
$$
我们设 $u=x+y,v=xy$,上式整理一下有
$$
xy(y+x)-a(x^2-y^2)=b
$$
替换后有
$$
uv-a(u^2-2v)=b
$$
$$
(u+2a)v=au^2+b
$$
$$
v=\frac{au^2+b}{u+2a}
$$
$$
v=\frac{au^2+b+2a^2u-2a^2u}{u+2a}=au+\frac{b-2a^2u-4a^3+4a^3}{u+2a}=au-2a^2+\frac{b+4a^3}{u+2a}
$$
可以看到 $u+2a$ 应该是 $b+4a^3$ 的一个因子,所以我们可以尝试一下分解 $b+4a^3$?因为知道 $a$,然后就能获得 $u$ 了。
这时会发现
$$
b+4a^3=n
$$
那么问题又回到分解 $n$ 上来了。
那么这里泄露了私钥 $d$ 的低位,这里尝试用coppersmith对其进行分解
考虑到 $p,q$ 的大小,如果$p,q$ 数量级差不多,平均分了 $n$ 的比特长度,那么除去已知的 $221$ 低位,我们大约还剩 $166$个低位, $2^{166} \le \frac{1}{2}n^{\beta^2-\epsilon}$ ,那么应该选择 $\beta = 0.5,\epsilon=0.034$
但是这里考虑道 $u+2a$ 是 $n$ 的一个因子,$4a^3+b=n$,$a$ 大约为 $n^{\frac{1}{3}}$,$v=xy=\frac{au^2+b}{u+2a}$,如果 $xy$ 的数量级差不多,那么应该 $x,y,u,a,b$ 都大约是 $n^{\frac{1}{3}}$,那么 $p,q$ 应该是 $258+515$ 这样子的分布。于是我们这里使用参数 $\beta=0.33,\epsilon=0.05$
(PS:由于e很大,所以个人PC挺难跑的,这里解题者是使用了20cores的计算机多线程去跑的。。。。)
exp来自:https://blog.cryptohack.org/cryptoctf2021-hard#polish
1 | # Part 1 : Factorization of n, written by rbtree |
有了 $p,q$ 后,我们获取 $u,v$,因为之前 $u=x+y,v=xy$,解一个方程我们获取 $x,y$,然后就能解密密文得到 $flag$ 了。
1 | # Part 2 : Calculating the Flag |
flag:CCTF{Par7ial_K3y_Exp0sure_At7ack_0n_L0w_3xP_RSA}
(PS:看这flag,$e$ 也不小啊,是不是放错了,,,,,)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com
文章标题:2021 CryptoCTF
文章字数:19.6k
本文作者:Van1sh
发布时间:2022-08-30, 13:30:00
最后更新:2023-03-07, 18:34:57
原始链接:http://jayxv.github.io/2022/08/30/2021 cryptoctf/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。